﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;

namespace IECAS.ERS.Services.Pop3
{
    #region enum ContentDisposition

    /// <summary>
    /// Content disposition.
    /// </summary>
    public enum Disposition
    {
        /// <summary>
        /// Content is attachment.
        /// </summary>
        Attachment = 0,

        /// <summary>
        /// Content is embbed resource.
        /// </summary>
        Inline = 1,

        /// <summary>
        /// Content is unknown.
        /// </summary>
        Unknown = 40
    }

    #endregion

    public class MimeParser
    {
        private string m_Headers = "";
        private string m_BoundaryID = "";
        private MemoryStream m_MsgStream = null;
        private ArrayList m_Entries = null;

        public MimeParser(byte[] msg)
        {
            m_MsgStream = new MemoryStream(msg);
            m_Headers = ParseHeaders(m_MsgStream);
            m_BoundaryID = ParseBoundaryID(m_Headers);
        }

        private string ParseHeaders(MemoryStream msgStrm)
        {
            /*3.1.  GENERAL DESCRIPTION
            A message consists of header fields and, optionally, a body.
            The  body  is simply a sequence of lines containing ASCII charac-
            ters.  It is separated from the headers by a null line  (i.e.,  a
            line with nothing preceding the CRLF).
            */
            string headers = "";
            TextReader r = new StreamReader(msgStrm);
            string line = r.ReadLine();
            while (line != null && line.Length != 0)
            {
                headers += line + "\r\n";
                line = r.ReadLine();
            }
            headers += "\r\n";
            return headers;
        }

        #region function ParseContentType

        /// <summary>
        /// Parse content type.
        /// </summary>
        /// <param name="headers"></param>
        /// <returns></returns>
        private string ParseContentType(string headers)
        {
            //	return ParseHeaderField("CONTENT-TYPE:",headers);
            using (TextReader r = new StreamReader(new MemoryStream(System.Text.Encoding.ASCII.GetBytes(headers))))
            {
                string line = r.ReadLine();
                while (line != null)
                {
                    if (line.ToUpper().StartsWith("CONTENT-TYPE:"))
                    {
                        return line.Substring(13).Trim();
                    }
                    line = r.ReadLine();
                }
            }
            return "";
        }

        #endregion

        #region function ParseBoundaryID

        /// <summary>
        /// Parse boundaryID.
        /// </summary>
        /// <param name="headers"></param>
        /// <returns></returns>
        internal string ParseBoundaryID(string headers)
        {
            using (TextReader r = new StreamReader(new MemoryStream(System.Text.Encoding.Default.GetBytes(headers))))
            {
                string line = r.ReadLine();
                while (line != null)
                {
                    int index = line.ToUpper().IndexOf("BOUNDARY=");
                    if (index > -1)//例如：【	boundary="----=_Part_31470_5483234.1285557639717"】
                    {
                        line = line.Substring(index + 9); // Remove charset=
                        // Charset may be in "" and without
                        if (line.StartsWith("\""))
                        {
                            return line.Substring(1, line.IndexOf("\"", 1) - 1);
                        }
                        else
                        {
                            int endIndex = line.Length;
                            if (line.IndexOf(" ") > -1)
                            {
                                endIndex = line.IndexOf(" ");
                            }
                            return line.Substring(0, endIndex);
                        }
                    }

                    line = r.ReadLine();
                    /*	int index = line.ToUpper().IndexOf("BOUNDARY=");
                        if(index > -1){	
                            line = line.Substring(index + 10); // Remove BOUNDARY="
                            return line.Substring(0,line.IndexOf("\""));
                        }
                        line = r.ReadLine();*/
                }
            }
            return "";
        }

        #endregion

        #region function ParseEntries

        /// <summary>
        /// Parses mime entries.
        /// </summary>
        /// <param name="msgStrm"></param>
        /// <param name="pos"></param>
        /// <param name="boundaryID"></param>
        internal ArrayList ParseEntries(MemoryStream msgStrm, int pos, string boundaryID)
        {
            ArrayList entries = null;

            // Entries are already parsed
            if (m_Entries != null)
            {
                return m_Entries;
            }

            entries = new ArrayList();

            // If message doesn't have entries (simple text message).
            if (this.ContentType.ToLower().IndexOf("text/") > -1)
            {
                entries.Add(new MimeEntry(msgStrm.ToArray(), this));
                m_Entries = entries;

                return m_Entries;
            }

            msgStrm.Position = pos;

            if (boundaryID.Length > 0)
            {
                MemoryStream strmEntry = new MemoryStream();
                StreamLineReader reader = new StreamLineReader(msgStrm);
                byte[] lineData = reader.ReadLine();

                // Search first entry
                while (lineData != null)
                {
                    string line = System.Text.Encoding.Default.GetString(lineData);
                    if (line.StartsWith("--" + boundaryID))
                    {
                        break;
                    }

                    lineData = reader.ReadLine();
                }

                // Start reading entries
                while (lineData != null)
                {
                    // Read entry data
                    string line = System.Text.Encoding.Default.GetString(lineData);
                    // Next boundary
                    if (line.StartsWith("--" + boundaryID) && strmEntry.Length > 0)
                    {
                        // Add Entry
                        entries.Add(new MimeEntry(strmEntry.ToArray(), this));

                        strmEntry.SetLength(0);
                    }
                    else
                    {
                        strmEntry.Write(lineData, 0, lineData.Length);
                        strmEntry.Write(new byte[] { (byte)'\r', (byte)'\n' }, 0, 2);
                    }

                    lineData = reader.ReadLine();
                }
            }

            return entries;
        }

        #endregion

        /// <summary>
        /// Gets messageID.
        /// </summary>
        public string ContentType
        {
            get { return ParseContentType(m_Headers); }
        }
    }
}
